package com.tianlan.blog.service.impl;

import java.util.Date;
import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang3.RandomStringUtils;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import com.sun.xml.bind.v2.TODO;
import com.tianlan.blog.config.UserIdAuditorBean;
import com.tianlan.blog.dao.SysOrganizationUserDao;
import com.tianlan.blog.dao.SysUserDao;
import com.tianlan.blog.dao.SysUserRoleDao;
import com.tianlan.blog.dto.CreateUser;
import com.tianlan.blog.dto.QueryUser;
import com.tianlan.blog.dto.UpdateUser;
import com.tianlan.blog.dto.UserInfo;
import com.tianlan.blog.entity.SysOrganizationUser;
import com.tianlan.blog.entity.SysUser;
import com.tianlan.blog.entity.SysUserRole;
import com.tianlan.blog.service.SysUserService;
import com.tianlan.common.base.BusinessException;
import com.tianlan.common.base.Constant;
import com.tianlan.common.page.MyPage;

import net.oschina.j2cache.CacheChannel;

@Service
public class SysUserServiceImpl implements SysUserService {

	@Autowired
	private SysUserDao sysUserDao;

	@Autowired
	private SysOrganizationUserDao sysOrganizationUserDao;

	@Autowired
	private SysUserRoleDao sysUserRoleDao;

	@Value("${system.defaultPwd}")
	private String defaultPwd;

	@Value("${system.defaultRoleId}")
	private Integer defaultRoleId;

	@Value("${system.defaultOrgId}")
	private int defaultOrgId;
	
    @Autowired
    private CacheChannel cacheChannel;
    
	@Override
	public List<Object[]> queryUserInfoList(QueryUser user,MyPage<UserInfo> page) {
		return sysUserDao.queryUserInfoList(user,page);
	}
	
	@Override
	public int queryUserInfoListCount(QueryUser user) {
		return sysUserDao.queryUserInfoListCount(user);
	}
    
	@Override
	public SysUser getUserByUserAccount(String userAccount) {
		return sysUserDao.findByUserAccountAndDelFlag(userAccount,"0");
	}

	@Override
	public boolean createUser(CreateUser user) {
		Integer isUser = sysUserDao.getIsUser(user);
		if (isUser != 0) {
			throw new BusinessException("账号已经存在");
		}
		if (null == user.getOrganizationId()) {
			user.setOrganizationId(defaultOrgId);
		}
		Integer roleId = user.getRoleId();
		List<Integer> roleIds = user.getRoleIds();
		if (null == roleId && CollectionUtils.isEmpty(roleIds)) {
			// 默认值，改成配置
			roleId = defaultRoleId;
		}
		List<String> areas = user.getAreas();
		if (!CollectionUtils.isEmpty(areas)) {
			user.setProvince(areas.get(Constant.Address.PROVINCE));
			user.setCity(areas.get(Constant.Address.CITY));
			user.setArea(areas.get(Constant.Address.AREA));
		}

		SysUser userEntity = new SysUser();
		BeanCopier.create(CreateUser.class, SysUser.class, false).copy(user, userEntity, null);
		String pwd = userEntity.getUserPassword();
		if (StringUtils.isEmpty(pwd)) {
			// 默认密码，配置文件配置
			pwd = defaultPwd;
		}
		String salt = RandomStringUtils.randomAlphanumeric(20);
		String cryptPwd = new Sha256Hash(pwd, salt).toHex();
		userEntity.setUserPassword(cryptPwd);
		userEntity.setSalt(salt);
		SysUser isCreate = sysUserDao.save(userEntity);
		boolean result = false;
		if (isCreate != null && !"".equals(isCreate)) {
			// 保存用户和组织机构的关系
			Integer organizationId = user.getOrganizationId();
			SysOrganizationUser orgUser = new SysOrganizationUser();
			orgUser.setUserId(userEntity.getId());
			orgUser.setOrganizationId(organizationId);
			sysOrganizationUserDao.save(orgUser);

			// 默认增加用户所在机构数据权限值，但是否有操作权限还是会根据资源权限判断
			// DataPermission dataPermission = new DataPermission();
			// dataPermission.setUserId(userEntity.getId());
			// dataPermission.setOrganizationId(organizationId);
			// dataPermissionService.save(dataPermission);

			// 保存用户角色信息
			user.setId(userEntity.getId());
			user.setUserPassword(cryptPwd);
			SysUserRole userRole = new SysUserRole();
			userRole.setUserId(userEntity.getId());
			if (!CollectionUtils.isEmpty(roleIds)) {
				UserIdAuditorBean auditorUserId = new UserIdAuditorBean();
				userRole.setCreator(auditorUserId.getUserId());
				userRole.setOperator(auditorUserId.getUserId());
				for (Integer role : roleIds) {
					userRole.setRoleId(role);
					int isUserRole = sysUserRoleDao.insertUserRole(userRole);
					if (isUserRole != 0) {
						result = true;
					}
				}
			} else {
				userRole.setRoleId(roleId);
				userRole = sysUserRoleDao.save(userRole);
				if (userRole != null && !"".equals(userRole)) {
					result = true;
				}
			}

		}
		return result;
	}

	/**
	 * {@link TODO}
	 */
	@Override
	@CacheEvict(value = "users", key = "'id_'.concat(#user.id)")
	public boolean updateUser(UpdateUser user) {
//		Integer isUser = sysUserDao.getIsUser(user);
//		if (isUser != 0) {
//			throw new BusinessException("账号已经存在");
//		}
		List<String> areas = user.getAreas();
		if (!CollectionUtils.isEmpty(areas)) {
			user.setProvince(areas.get(Constant.Address.PROVINCE));
			user.setCity(areas.get(Constant.Address.CITY));
			user.setArea(areas.get(Constant.Address.AREA));
		}
		SysUser userEntity = new SysUser();
		BeanCopier.create(UpdateUser.class, SysUser.class, false).copy(user, userEntity, null);
//		String pwd = userEntity.getUserPassword();
//		if (!StringUtils.isEmpty(pwd)) {
//			String salt = RandomStringUtils.randomAlphanumeric(20);
//			String cryptPwd = new Sha256Hash(pwd, salt).toHex();
//			userEntity.setUserPassword(cryptPwd);
//			userEntity.setSalt(salt);
//		}
		userEntity.setUpdateTime(new Date());
		UserIdAuditorBean auditorUserId = new UserIdAuditorBean();
		userEntity.setOperator(auditorUserId.getUserId());
		int isUpdateUser = sysUserDao.updateUser(userEntity);
		
		Integer organizationId = user.getOrganizationId();
		SysOrganizationUser orgUserOld = sysOrganizationUserDao.findOneByUserIdAndOrganizationIdAndDelFlag(userEntity.getId(),
				organizationId,"0");
		if (null == orgUserOld && null != organizationId) {
			SysOrganizationUser orgUserRemove = sysOrganizationUserDao.findOneByUserIdAndDelFlag(userEntity.getId(),"0");
			// 删除旧机构的组织机构关系
			sysOrganizationUserDao.delete(orgUserRemove);
			// 保存用户和组织机构的关系
			SysOrganizationUser orgUser = new SysOrganizationUser();
			orgUser.setUserId(userEntity.getId());
			orgUser.setOrganizationId(organizationId);
			sysOrganizationUserDao.save(orgUser);
		}

		boolean result = isUpdateUser != 0;
		List<Integer> roleIds = user.getRoleIds();
		if (isUpdateUser != 0 && (null != user.getRoleId() || !CollectionUtils.isEmpty(roleIds))) {
			// 多个用户角色关系
			if (!CollectionUtils.isEmpty(roleIds)) {
				List<SysUserRole> userRoleList = sysUserRoleDao.findByUserIdAndDelFlag(userEntity.getId(),"0");
				if (!CollectionUtils.isEmpty(userRoleList)) {
					for (SysUserRole role : userRoleList) {
						// 如果这个用户与角色关系不存在，则删除
						if (!roleIds.contains(role.getRoleId())) {
							SysUserRole userRoleRemove = sysUserRoleDao.findOneByUserIdAndRoleIdAndDelFlag(userEntity.getId(),
									role.getRoleId(),"0");
							sysUserRoleDao.delete(userRoleRemove);
						}
					}
				}
			} else if (null != user.getRoleId()) {
				// 多个用户角色关系
				SysUserRole userRole = new SysUserRole();
				userRole.setUserId(userEntity.getId());
				userRole.setRoleId(user.getRoleId());
				List<SysUserRole> userRoleList = sysUserRoleDao.findOneByRoleIdAndUserIdAndDelFlag(user.getRoleId(),
						userEntity.getId(),"0");
				if (CollectionUtils.isEmpty(userRoleList)) {
					sysUserRoleDao.deleteUserRoleByUserId(userEntity.getId());
					SysUserRole isUserRole = sysUserRoleDao.save(userRole);
					if (isUserRole != null && !"".equals(isUserRole)) {
						result = true;
					}
				}
			}
			cacheChannel.evict("roles", "user_id_" + userEntity.getId());
		}
		return result;
	}

	@Override
	@CacheEvict(value = "users", key = "'id_'.concat(#userId)")
	public boolean deleteUser(Integer userId) {	
		int userDelete = sysUserDao.deleteUser(userId);
		if(userDelete != 0){
			sysOrganizationUserDao.deleteOrganizationUser(userId);
			sysUserRoleDao.deleteUserRoleByUserId(userId);
			return true;
		}else{
			return false;
		}
	}
	
	@Override
	public long checkUserAccount(CreateUser user) {
		@SuppressWarnings("serial")
		Specification<SysUser> specification = new Specification<SysUser>() {
			@Override
			public Predicate toPredicate(Root<SysUser> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				String userAccount = user.getUserAccount();
				Predicate userAccountPredicate = cb.equal(root.get("userAccount"), userAccount);
				if (null != user.getId()) {
					Predicate userIdPredicate = cb.notEqual(root.get("id"), user.getId());
					return cb.and(userAccountPredicate, userIdPredicate);
				}
				return cb.and(userAccountPredicate);
			}
		};
		return sysUserDao.count(specification);
	}

	@Override
	public long checkUserNickname(CreateUser user) {
		@SuppressWarnings("serial")
		Specification<SysUser> specification = new Specification<SysUser>() {
			@Override
			public Predicate toPredicate(Root<SysUser> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				String userNickName = user.getUserNickName();
				Predicate userNickNamePredicate = cb.equal(root.get("userNickName"), userNickName);
				if (null != user.getId()) {
					Predicate userIdPredicate = cb.notEqual(root.get("id"), user.getId());
					return cb.and(userNickNamePredicate, userIdPredicate);
				}
				return cb.and(userNickNamePredicate);
			}
		};
		return sysUserDao.count(specification);
	}

	@Override
	public long checkUserMobile(CreateUser user) {
		@SuppressWarnings("serial")
		Specification<SysUser> specification = new Specification<SysUser>() {
			@Override
			public Predicate toPredicate(Root<SysUser> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				String userMobile = user.getUserMobile();
				Predicate userMobilePredicate = cb.equal(root.get("userMobile"), userMobile);
				if (null != user.getId()) {
					Predicate userIdPredicate = cb.notEqual(root.get("id"), user.getId());
					return cb.and(userMobilePredicate, userIdPredicate);
				}
				return cb.and(userMobilePredicate);
			}
		};
		return sysUserDao.count(specification);
	}

	@Override
	public long checkUserEmail(CreateUser user) {
		@SuppressWarnings("serial")
		Specification<SysUser> specification = new Specification<SysUser>() {
			@Override
			public Predicate toPredicate(Root<SysUser> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				String userEmail = user.getUserEmail();
				Predicate userEmailPredicate = cb.equal(root.get("userEmail"), userEmail);
				if (null != user.getId()) {
					Predicate userIdPredicate = cb.notEqual(root.get("id"), user.getId());
					return cb.and(userEmailPredicate, userIdPredicate);
				}
				return cb.and(userEmailPredicate);
			}
		};
		return sysUserDao.count(specification);
	}

}
